package com.wenx.v3system.modular.cloud.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wenx.v3core.error.BusinessException;
import com.wenx.v3secure.utils.LoginUser;
import com.wenx.v3system.modular.cloud.domain.dto.SysRoleDto;
import com.wenx.v3system.modular.cloud.domain.maps.SysRoleMap;
import com.wenx.v3system.modular.cloud.domain.po.SysRole;
import com.wenx.v3system.modular.cloud.domain.po.SysPermission;
import com.wenx.v3system.modular.cloud.domain.query.SysRoleQuery;
import com.wenx.v3system.modular.cloud.mapper.SysRoleMapper;
import com.wenx.v3system.modular.cloud.mapper.SysPermissionMapper;
import com.wenx.v3system.modular.cloud.service.SysRoleMenuService;
import com.wenx.v3system.modular.cloud.service.SysRoleRestService;
import com.wenx.v3system.modular.cloud.service.SysRolePermissionService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 系统角色服务实现类
 * 基于Enhanced RBAC权限模型
 * 使用v3-system数据源
 *
 * @author wenx
 * @since 1.0.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysRoleRestServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleRestService {

    // 缓存常量
    private static final String ROLE_CACHE = "sys:role";
    private static final String ROLE_PERMISSIONS_CACHE = "sys:role:permissions";
    private static final String USER_ROLES_CACHE = "sys:user:roles";
    private static final String ROLE_MENUS_CACHE = "sys:role:menus";

    private final SysRoleMenuService roleMenuService;
    private final SysRolePermissionService rolePermissionService;
    private final SysPermissionMapper permissionMapper;

    @Override
    public IPage<?> page(SysRoleQuery query) {
        LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<SysRole>()
                .eq(SysRole::getDeleted, false)
                .orderByDesc(SysRole::getCreateTime);

        IPage<SysRole> result = super.page(new Page<>(query.getCurrent(), query.getSize()), wrapper);
        return result.convert(this::convertToDto);
    }

    @Override
    public List<SysRole> all() {
        LambdaQueryWrapper<SysRole> wrapper = buildDataScopeWrapper();
        return super.list(wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {ROLE_CACHE, ROLE_PERMISSIONS_CACHE}, allEntries = true)
    public void add(SysRoleDto dto) {
        if (existsByCode(dto.getCode(), null)) {
            throw new BusinessException("角色编码已存在: " + dto.getCode());
        }

        SysRole role = SysRoleMap.INSTANCE.toPo(dto);
        if (!super.save(role)) {
            throw new BusinessException("角色新增失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {ROLE_CACHE, ROLE_PERMISSIONS_CACHE, USER_ROLES_CACHE}, allEntries = true)
    public void delete(Serializable id) {
        SysRole role = super.getById(id);
        if (role == null) {
            throw new BusinessException("角色不存在，ID: " + id);
        }

        if (!super.removeById(id)) {
            throw new BusinessException("角色删除失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {ROLE_CACHE, ROLE_PERMISSIONS_CACHE}, allEntries = true)
    public void update(SysRoleDto dto) {
        if (dto.getId() == null) {
            throw new BusinessException("角色ID不能为空");
        }

        SysRole existingRole = super.getById(dto.getId());
        if (existingRole == null) {
            throw new BusinessException("角色不存在，ID: " + dto.getId());
        }

        if (existsByCode(dto.getCode(), dto.getId())) {
            throw new BusinessException("角色编码已存在: " + dto.getCode());
        }

        BeanUtils.copyProperties(dto, existingRole, "id", "createTime", "createBy");
        if (!super.updateById(existingRole)) {
            throw new BusinessException("角色更新失败");
        }
    }

    @Override
    @Cacheable(value = ROLE_CACHE, key = "#id")
    public Object get(Serializable id) {
        return super.getById(id);
    }

    @Override
    @Cacheable(value = USER_ROLES_CACHE, key = "#userId")
    public List<SysRoleDto> getUserRoles(Long userId) {
        if (userId == null) {
            throw new BusinessException("用户ID不能为空");
        }
        // TODO: 实现用户角色查询逻辑
        return Collections.emptyList();
    }

    @Override
    @Cacheable(value = ROLE_PERMISSIONS_CACHE, key = "#roleId")
    public Set<String> getRolePermissions(Long roleId) {
        if (roleId == null) {
            throw new BusinessException("角色ID不能为空");
        }
        return rolePermissionService.getPermissionCodesByRoleId(roleId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = ROLE_PERMISSIONS_CACHE, key = "#roleId")
    public void assignPermissionsToRoleByData(Long roleId, Object permissionData) {
        if (roleId == null) {
            throw new BusinessException("角色ID不能为空");
        }
        if (permissionData == null) {
            throw new BusinessException("权限数据不能为空");
        }

        log.info("处理角色权限分配，角色ID: {}, 数据类型: {}", roleId, permissionData.getClass().getSimpleName());
        
        if (!(permissionData instanceof List)) {
            throw new BusinessException("权限数据格式错误，应为数组类型");
        }
        
        List<?> permissionList = (List<?>) permissionData;
        if (permissionList.isEmpty()) {
            // 空列表，清空权限
            log.info("权限列表为空，清空角色权限，角色ID: {}", roleId);
            assignPermissionsToRole(roleId, new ArrayList<>());
            return;
        }
        
        // 根据首个元素的类型判断数据格式
        Object firstElement = permissionList.get(0);
        if (isNumericType(firstElement)) {
            // 数字类型，视为权限ID
            List<Long> permissionIds = convertToPermissionIds(permissionList);
            log.info("识别为权限ID列表，数量: {}", permissionIds.size());
            assignPermissionsToRole(roleId, permissionIds);
        } else {
            // 字符串类型，视为权限代码
            List<String> permissionCodes = convertToPermissionCodes(permissionList);
            log.info("识别为权限代码列表，数量: {}", permissionCodes.size());
            assignPermissionsByCode(roleId, permissionCodes);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = ROLE_PERMISSIONS_CACHE, key = "#roleId")
    public void assignPermissionsToRole(Long roleId, List<Long> permissionIds) {
        if (roleId == null) {
            throw new BusinessException("角色ID不能为空");
        }
        if (permissionIds == null) {
            permissionIds = new ArrayList<>();
        }

        SysRole role = super.getById(roleId);
        if (role == null) {
            throw new BusinessException("角色不存在，ID: " + roleId);
        }
        
        // 使用角色权限服务进行权限分配
        rolePermissionService.setRolePermissions(roleId, permissionIds);
        log.info("角色权限分配完成，角色ID: {}, 权限数量: {}", roleId, permissionIds.size());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = ROLE_PERMISSIONS_CACHE, key = "#roleId")
    public void assignPermissionsByCode(Long roleId, List<String> permissionCodes) {
        if (roleId == null) {
            throw new BusinessException("角色ID不能为空");
        }
        if (ObjectUtil.isEmpty(permissionCodes)) {
            // 空列表，清空权限
            rolePermissionService.clearRolePermissions(roleId);
            log.info("角色权限清空完成，角色ID: {}", roleId);
            return;
        }

        SysRole role = super.getById(roleId);
        if (role == null) {
            throw new BusinessException("角色不存在，ID: " + roleId);
        }
        
        // 通过权限代码获取权限ID
        List<Long> permissionIds = getPermissionIdsByCodes(permissionCodes);
        
        // 使用角色权限服务进行权限分配
        rolePermissionService.setRolePermissions(roleId, permissionIds);
        log.info("角色权限分配完成（按代码），角色ID: {}, 权限数量: {}", roleId, permissionIds.size());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = ROLE_PERMISSIONS_CACHE, key = "#roleId")
    public void removeRolePermissionsByCode(Long roleId, List<String> permissionCodes) {
        if (roleId == null) {
            throw new BusinessException("角色ID不能为空");
        }
        if (ObjectUtil.isEmpty(permissionCodes)) {
            return;
        }
        
        // 通过权限代码获取权限ID
        List<Long> permissionIds = getPermissionIdsByCodes(permissionCodes);
        
        // 使用角色权限服务移除权限
        rolePermissionService.removePermissionsFromRole(roleId, permissionIds);
        log.info("角色权限移除完成（按代码），角色ID: {}, 权限数量: {}", roleId, permissionIds.size());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = ROLE_PERMISSIONS_CACHE, key = "#roleId")
    public void removeRolePermissions(Long roleId, List<Long> permissionIds) {
        if (roleId == null) {
            throw new BusinessException("角色ID不能为空");
        }
        if (ObjectUtil.isEmpty(permissionIds)) {
            throw new BusinessException("权限ID列表不能为空");
        }
        
        // 使用角色权限服务移除权限
        rolePermissionService.removePermissionsFromRole(roleId, permissionIds);
        log.info("角色权限移除完成，角色ID: {}, 权限数量: {}", roleId, permissionIds.size());
    }

    @Override
    public boolean hasPermission(Long roleId, String permission) {
        if (roleId == null || !StringUtils.hasText(permission)) {
            return false;
        }
        Set<String> rolePermissions = getRolePermissions(roleId);
        return rolePermissions.contains(permission);
    }

    @Override
    public List<SysRoleDto> getChildRoles(Long parentRoleId) {
        if (parentRoleId == null) {
            throw new BusinessException("父角色ID不能为空");
        }

        LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysRole::getDeleted, false);
        // TODO: 根据实际的SysRole实体字段调整
        // .eq(SysRole::getParentId, parentRoleId)
        // .orderByAsc(SysRole::getSort);

        List<SysRole> childRoles = super.list(wrapper);
        return childRoles.stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {ROLE_CACHE, USER_ROLES_CACHE}, allEntries = true)
    public void enableRole(Long roleId) {
        updateRoleStatus(roleId, 1);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {ROLE_CACHE, USER_ROLES_CACHE}, allEntries = true)
    public void disableRole(Long roleId) {
        updateRoleStatus(roleId, 0);
    }

    @Override
    public boolean existsByCode(String code, Long excludeId) {
        if (!StringUtils.hasText(code)) {
            return false;
        }

        LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysRole::getCode, code)
               .eq(SysRole::getDeleted, false);

        if (excludeId != null) {
            wrapper.ne(SysRole::getId, excludeId);
        }

        return super.count(wrapper) > 0;
    }

    /**
     * 构建数据权限查询条件
     */
    private LambdaQueryWrapper<SysRole> buildDataScopeWrapper() {
        LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysRole::getDeleted, false);
        
        if (LoginUser.isSuperAdmin()) {
            // 超级管理员可以查看所有角色
            return wrapper.orderByDesc(SysRole::getCreateTime);
        }
        
        // 普通用户数据隔离
        Long currentUserId = LoginUser.getUserId();
        List<Long> dataScopeList = LoginUser.getDataScopeList();
        
        if (currentUserId != null) {
            if (ObjectUtil.isNotEmpty(dataScopeList)) {
                // 按数据权限范围过滤
                // TODO: 根据实际的SysRole实体字段调整
                // wrapper.in(SysRole::getDepartmentId, dataScopeList);
                wrapper.eq(SysRole::getCreateBy, currentUserId);
            } else {
                // 只能查看自己创建的角色
                wrapper.eq(SysRole::getCreateBy, currentUserId);
            }
        } else {
            // 无用户信息，返回空结果
            wrapper.eq(SysRole::getId, -1L);
        }
        
        return wrapper.orderByDesc(SysRole::getCreateTime);
    }

    /**
     * 转换为DTO
     */
    private SysRoleDto convertToDto(SysRole role) {
        return SysRoleMap.INSTANCE.toDto(role);
    }

    /**
     * 更新角色状态
     */
    private void updateRoleStatus(Long roleId, Integer status) {
        if (roleId == null) {
            throw new BusinessException("角色ID不能为空");
        }

        SysRole role = super.getById(roleId);
        if (role == null) {
            throw new BusinessException("角色不存在，ID: " + roleId);
        }

        role.setStatus(status);
        if (!super.updateById(role)) {
            throw new BusinessException("角色状态更新失败");
        }
    }

    /**
     * 通过权限代码获取权限ID列表
     */
    private List<Long> getPermissionIdsByCodes(List<String> permissionCodes) {
        if (CollectionUtils.isEmpty(permissionCodes)) {
            return Collections.emptyList();
        }

        LambdaQueryWrapper<SysPermission> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(SysPermission::getCode, permissionCodes)
               .eq(SysPermission::getDeleted, false)
               .eq(SysPermission::getStatus, 1);

        List<SysPermission> permissions = permissionMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(permissions)) {
            log.warn("未找到有效的权限记录，权限代码: {}", permissionCodes);
            return Collections.emptyList();
        }

        List<Long> permissionIds = permissions.stream()
                .map(SysPermission::getId)
                .collect(Collectors.toList());

        log.info("权限代码转换为ID: {} -> {}", permissionCodes, permissionIds);
        return permissionIds;
    }

    /**
     * 判断对象是否为数字类型
     */
    private boolean isNumericType(Object obj) {
        if (obj instanceof Number) {
            return true;
        }
        if (obj instanceof String) {
            try {
                Long.parseLong((String) obj);
                return true;
            } catch (NumberFormatException e) {
                return false;
            }
        }
        return false;
    }

    /**
     * 转换为权限ID列表
     */
    private List<Long> convertToPermissionIds(List<?> permissionList) {
        return permissionList.stream()
                .map(item -> {
                    if (item instanceof Number) {
                        return ((Number) item).longValue();
                    } else {
                        try {
                            return Long.parseLong(item.toString());
                        } catch (NumberFormatException e) {
                            log.warn("无法解析权限ID: {}", item);
                            return null;
                        }
                    }
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    /**
     * 转换为权限代码列表
     */
    private List<String> convertToPermissionCodes(List<?> permissionList) {
        return permissionList.stream()
                .map(Object::toString)
                .collect(Collectors.toList());
    }

    @Override
    @Cacheable(value = ROLE_MENUS_CACHE, key = "#roleId")
    public List<Long> getRoleMenus(Long roleId) {
        if (roleId == null) {
            throw new BusinessException("角色ID不能为空");
        }
        return roleMenuService.getMenuIdsByRoleId(roleId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = ROLE_MENUS_CACHE, key = "#roleId")
    public void assignMenusToRole(Long roleId, List<Long> menuIds) {
        if (roleId == null) {
            throw new BusinessException("角色ID不能为空");
        }
        
        // 验证角色是否存在
        SysRole role = super.getById(roleId);
        if (role == null) {
            throw new BusinessException("角色不存在，ID: " + roleId);
        }
        
        roleMenuService.assignMenusToRole(roleId, menuIds);
        log.info("角色菜单权限分配成功，角色ID: {}, 菜单数量: {}", roleId, 
                 menuIds != null ? menuIds.size() : 0);
    }
}
